<style>
.container {
  position: absolute;
  /* background-color: aqua; */
  padding: 10px;
  border: 1px solid #bbbbbb;
}
</style>
<template>
  <div class="container" @mousemove="onMouseMove" @mousedown="onMouseDown" @mouseup="onMouseUp"
    :style="{
      height: height + 'px',
      width: width + 'px',
      left: left + 'px',
      top: top + 'px',
    }" :id="chartDOMID" ref="chart-container">
    <slot></slot>
  </div>
</template>

<script lang="ts">
import {
  ContainerLayout
} from "./dragcontainers";
import { defineComponent, PropType } from "vue";

function getEventLocation(
  evt: MouseEvent,
  parent: HTMLElement
): { offsetX: number; offsetY: number } | null {
  var offsetX = evt.offsetX;
  var offsetY = evt.offsetY;
  const path = evt.composedPath() as HTMLDivElement[];
  if (path == null) {
    return null;
  }
  for (const elem of path) {
    if (elem == parent) {
      break;
    }
    offsetX += elem.offsetLeft;
    offsetY += elem.offsetTop;
  }
  return {
    offsetX,
    offsetY,
  };
}

export default defineComponent({
  name: "DraggingContainer",
  emits: ["container-changed"],
  props: {
    slotComponentID: {
      type: String,
      required: true,
    },
    // initialLayout: {
    //   type: Object as PropType<ContainerLayout>,
    //   required: true
    // }
  },
  data() {
    return {
      selectionItems: {} as any,
      unchangeableItems: {} as any,
      chartDOMID: `${Math.random()}`,
      clientX: 0,
      clientY: 0,
      height: 200,
      width: 200,
      left: 0,
      top: 0,
      requestSendPosChanged: false,
      timer: 0,
      dragMode: "move" as string, // 'move' 'resize'
      resizeDir: "", // "n", "nw" ...
    };
  },
  mounted() {
    this.timer = window.setInterval(() => {
      if (this.requestSendPosChanged) {
        const layout = {
          left: this.left,
          top: this.top,
          height: this.height,
          width: this.width,
        };
        this.$emit("container-changed", layout);
        this.requestSendPosChanged = false;
      }
    }, 100);
  },
  beforeUnmount() {
    window.clearInterval(this.timer);
  },
  methods: {
    updateInitialLayout(initialLayout: ContainerLayout) {
      this.left = initialLayout.left
      this.top = initialLayout.top
      this.width = initialLayout.width
      this.height = initialLayout.height
      this.requestSendPosChanged = true
    },
    onMouseDown(evt: MouseEvent) {
      const direc = this.getDirection(evt);
      let container = document.getElementById(
        this.chartDOMID
      ) as HTMLDivElement;
      if (container == null) {
        throw Error;
      }
      if (direc == "") {
        this.dragMode = "move";
        container.style.cursor = "default";
        container.style.zIndex = "100";
        // 如果此时同时按下了Ctrl或者Command，就将图标变为move
        console.log("button down", evt.buttons, evt.ctrlKey)
        if (evt.buttons === 1 && (evt.ctrlKey || evt.metaKey)) {
          container.style.cursor = "move"
        }
      } else {
        this.dragMode = "resize";
        container.style.cursor = direc + "-resize";
        this.resizeDir = direc;
        const mouseMoveHandlerDuringResizing = (evt: MouseEvent) => {
          if (direc.indexOf("e") !== -1) {
            this.width += evt.movementX;
          }

          // 鼠标按下的位置在上部，修改高度
          if (direc.indexOf("n") !== -1) {
            this.height += -evt.movementY;
            this.top += evt.movementY;
          }
          // 鼠标按下的位置在底部，修改高度
          if (direc.indexOf("s") !== -1) {
            this.height += evt.movementY;
          }

          // 鼠标按下的位置在左边，修改宽度
          if (direc.indexOf("w") !== -1) {
            this.width += -evt.movementX;
            this.left += evt.movementX;
          }
          this.requestSendPosChanged = true;
        };
        document.addEventListener("mousemove", mouseMoveHandlerDuringResizing);
        document.addEventListener("mouseup", () => {
          document.removeEventListener("mousemove", mouseMoveHandlerDuringResizing);
        });
      }
    },
    onMouseUp(evt: MouseEvent) {
      let container = document.getElementById(
        this.chartDOMID
      ) as HTMLDivElement;
      if (container == null) {
        throw Error;
      }
      container.style.cursor = "default";
      container.style.zIndex = "";
      this.dragMode = "move";
    },
    getDirection(ev: MouseEvent): string {
      const container = this.$refs["chart-container"] as any;
      if (container == null) {
        return "";
      }
      let xP, yP, offset, dir;
      dir = "";
      const loc = getEventLocation(ev, container);
      if (loc == null) {
        return "";
      }
      const { offsetX, offsetY } = loc;

      xP = offsetX;
      yP = offsetY;
      offset = 10;

      if (yP < offset) dir += "n";
      else if (yP > container.offsetHeight - offset) dir += "s";
      if (xP < offset) dir += "w";
      else if (xP > container.offsetWidth - offset) dir += "e";
      return dir;
    },
    onMouseMove(evt: MouseEvent) {
      const direc = this.getDirection(evt);
      const container = this.$refs["chart-container"] as any;
      if (container == null) {
        throw Error;
      }

      if (direc != "") { // 调整组件大小时
        container.style.cursor = direc + "-resize";
      } else { // 鼠标一般移动时
        // 如果正在移动组件
        if (evt.buttons === 1 && (evt.ctrlKey || evt.metaKey)) {
          container.style.cursor = "move";
          if (this.dragMode == "move") {
            this.top += evt.movementY;
            this.left += evt.movementX;
          }
          this.requestSendPosChanged = true;
        } else { // 如果没在移动组件，就将指针置为默认
          container.style.cursor = "default";
        }
      }

    },
  },
});
</script>
